#include "Precomp.h"
#include "ltInputManager.h"

#include <OIS/OISInputManager.h>
#include <OgreRenderWindow.h>
#include "ltGraphicManager.h"
#include <boost/bind.hpp>

namespace Lotus
{
	LT_IMPLEMENT_SINGLETON(InputManager)

	InputManager::InputManager()
	{
		inputEnabled=true;
		oisInputManager = NULL;
		oisKeyboard = NULL;
		oisMouse = NULL;
	}

	bool InputManager::init(Ogre::RenderWindow& ogreRenderWindow,bool show)
	{
		/// Input create
		OIS::ParamList pl;
		size_t windowHnd = 0;
		std::ostringstream windowHndStr;
		ogreRenderWindow.getCustomAttribute("WINDOW", &windowHnd);
		windowHndStr << windowHnd;
		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
		if(show)
		{
			pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
			pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
		}

		oisInputManager = OIS::InputManager::createInputSystem(pl);

		if(oisInputManager->numKeyboards() > 0)
		{
			oisKeyboard = static_cast<OIS::Keyboard*>(oisInputManager->createInputObject(OIS::OISKeyboard, true));
			oisKeyboard->setEventCallback(this);
		}
		if(oisInputManager->numMice() > 0)
		{
			oisMouse    = static_cast<OIS::Mouse*>(oisInputManager->createInputObject(OIS::OISMouse, true));
			oisMouse->setEventCallback(this);
		}
		windowResized(&ogreRenderWindow);

		updateConnection = GraphicManager::getInstance().FrameRenderingQueuedEvent.connect(boost::bind(&InputManager::inputUpdate,this,_1));

		Ogre::WindowEventUtilities::addWindowEventListener(&ogreRenderWindow, this);
		return true;
	}

	void InputManager::windowResized(Ogre::RenderWindow* ogreRenderWindow)
	{
		unsigned int width, height, depth;
		int left, top;
		ogreRenderWindow->getMetrics(width, height, depth, left, top);
		const OIS::MouseState &ms = oisMouse->getMouseState();
		ms.width = width;
		ms.height = height;
	}

	void InputManager::showMouseCursor(bool show)
	{
		/// Input destroy
		if(oisKeyboard)
		{
			oisInputManager->destroyInputObject(oisKeyboard);
			oisKeyboard = NULL;
		}
		if(oisMouse)
		{
			oisInputManager->destroyInputObject(oisMouse);
			oisMouse = NULL;
		}
		if(oisInputManager)
		{
			OIS::InputManager::destroyInputSystem(oisInputManager);
			oisInputManager = NULL;
		}

		OIS::ParamList pl;
		size_t windowHnd = 0;
		std::ostringstream windowHndStr;
		Lotus::GraphicManager::getInstance().getOgreRenderWindow()->getCustomAttribute("WINDOW", &windowHnd);
		windowHndStr << windowHnd;
		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
		if(show)
		{
			pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
			pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
		}

		oisInputManager = OIS::InputManager::createInputSystem(pl);
		if(oisInputManager->numKeyboards() > 0)
		{
			oisKeyboard = static_cast<OIS::Keyboard*>(oisInputManager->createInputObject(OIS::OISKeyboard, true));
			oisKeyboard->setEventCallback(this);
		}
		if(oisInputManager->numMice() > 0)
		{
			oisMouse    = static_cast<OIS::Mouse*>(oisInputManager->createInputObject(OIS::OISMouse, true));
			oisMouse->setEventCallback(this);
		}

		windowResized(Lotus::GraphicManager::getInstance().getOgreRenderWindow());
	}

	void InputManager::setInputEnabled(bool enabled)
	{
		if(inputEnabled&&!enabled)//turn off
		{
			updateConnection.disconnect();
		}
		if(!inputEnabled&&enabled)//turn on
		{
			updateConnection = GraphicManager::getInstance().FrameRenderingQueuedEvent.connect(boost::bind(&InputManager::inputUpdate,this,_1));
		}
		inputEnabled=enabled;
	}

	bool InputManager::isInputEnabled() const
	{
		return inputEnabled;
	}

	InputManager::~InputManager()
	{
		Ogre::WindowEventUtilities::removeWindowEventListener(Lotus::GraphicManager::getInstance().getOgreRenderWindow(), this);

		if(updateConnection.connected())
			updateConnection.disconnect();

		/// Input destroy
		if(oisKeyboard)
		{
			oisInputManager->destroyInputObject(oisKeyboard);
			oisKeyboard = NULL;
		}
		if(oisMouse)
		{
			oisInputManager->destroyInputObject(oisMouse);
			oisMouse = NULL;
		}
		if(oisInputManager)
		{
			OIS::InputManager::destroyInputSystem(oisInputManager);
			oisInputManager = NULL;
		}
	}

	OIS::Keyboard* InputManager::getKeyboard() const
	{
		return oisKeyboard;
	}
	
	OIS::Mouse* InputManager::getMouse() const
	{
		return oisMouse;
	}

	bool InputManager::keyPressed(const OIS::KeyEvent& arg)
	{
		for(std::list<Lotus::KeyboardListener*>::const_iterator itr = KeyListenerList.begin(); itr != KeyListenerList.end(); ++itr)
		{
			(*itr)->keyPressed(arg);
		}

		KeyPressedEvent(arg);
		return true;
	}

	bool InputManager::keyReleased(const OIS::KeyEvent& arg)
	{
		for(std::list<Lotus::KeyboardListener*>::const_iterator itr = KeyListenerList.begin(); itr != KeyListenerList.end(); ++itr)
		{
			(*itr)->keyReleased(arg);
		}

		KeyReleasedEvent(arg);
		return true;
	}

	bool InputManager::mouseMoved(const OIS::MouseEvent& arg)
	{
		for(std::list<Lotus::MouseListener*>::const_iterator itr = MouseListenerList.begin(); itr != MouseListenerList.end(); ++itr)
		{
			(*itr)->mouseMoved(arg);
		}

		MouseMovedEvent(arg);
		return true;
	}

	bool InputManager::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
	{
		for(std::list<Lotus::MouseListener*>::const_iterator itr = MouseListenerList.begin(); itr != MouseListenerList.end(); ++itr)
		{
			(*itr)->mousePressed(arg, id);
		}

		MousePressedEvent(arg, id);
		return true;
	}

	bool InputManager::mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
	{
		for(std::list<Lotus::MouseListener*>::const_iterator itr = MouseListenerList.begin(); itr != MouseListenerList.end(); ++itr)
		{
			(*itr)->mouseReleased(arg, id);
		}

		MouseReleasedEvent(arg, id);
		return true;
	}

	void InputManager::addKeyboardListener(Lotus::KeyboardListener* listener)
	{
		KeyListenerList.push_back(listener);
	}

	void InputManager::removeKeyboardListener(Lotus::KeyboardListener* listener)
	{
		KeyListenerList.remove(listener);
	}

	void InputManager::addMouseListener(Lotus::MouseListener* listener)
	{
		MouseListenerList.push_back(listener);
	}

	void InputManager::removeMouseListener(Lotus::MouseListener* listener)
	{
		MouseListenerList.remove(listener);
	}

	void InputManager::inputUpdate(const Ogre::FrameEvent& evt)
	{
		oisKeyboard->capture();
		oisMouse->capture();
	}

}